
package com.scs.application.modules.base.service.impl;

import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.scs.application.consts.SerialRuleConsts;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.model.CommonResult;
import com.scs.application.core.serial.SerialUtils;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.thread.BatchSaveTask;
import com.scs.application.core.thread.DefaultSaveHandler;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.dto.ExcelHospitalMaterialDTO;
import com.scs.application.modules.base.dto.ExcelMaterialDTO;
import com.scs.application.modules.base.dto.HospitalMaterialDTO;
import com.scs.application.modules.base.dto.MaterialApplicantAddBatchDto;
import com.scs.application.modules.base.entity.*;
import com.scs.application.modules.base.mapper.HospitalMaterialMapper;
import com.scs.application.modules.base.mapper.HospitalSupplierMapper;
import com.scs.application.modules.base.request.HospitalMaterialQueryRequest;
import com.scs.application.modules.base.request.HospitalMaterialRequest;
import com.scs.application.modules.base.service.*;
import com.scs.application.modules.base.vo.HospitalMaterialVO;
import com.scs.application.modules.base.vo.MaterialVO;
import com.scs.application.modules.thirdparty.erp.request.MaterialRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StopWatch;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * HospitalMaterial service 实现
 */
@Slf4j
@AllArgsConstructor
@Service
@Transactional(rollbackFor = Exception.class)
public class HospitalMaterialServiceImpl extends BaseServiceImpl<HospitalMaterialMapper, HospitalMaterial> implements HospitalMaterialService {

    private final MaterialService materialService;

    private final ManufacturerService manufacturerService;

    private final MaterialSpecService materialSpecService;

    private final SupplierService supplierService;

    private final HospitalService hospitalService;

    private final HospitalSupplierMapper hospitalSupplierMapper;

    @Override
    public List<HospitalMaterial> list(HospitalMaterialQueryRequest request) {
        if (UserUtils.isHospital()) {
            request.setHospitalId(request.getHospitalId());
        } else if (UserUtils.isSupplier()) {
            request.setSupplierId(request.getSupplierId());
        }
        //request.setInactive(HospitalMaterial.ACTIVATE);
        return baseMapper.list(request);
    }

    @Override
    public IPage<HospitalMaterial> page(HospitalMaterialQueryRequest request) {

        if (UserUtils.isHospital()) {
            request.setHospitalId(UserUtils.getHospitalId());
        } else if (UserUtils.isSupplier()) {
            request.setSupplierId(UserUtils.getSupplierId());
        }
        //request.setInactive(HospitalMaterial.ACTIVATE);
        return this.baseMapper.page(request.getPage(), request);
    }

    @Override
    public List<HospitalMaterialVO> listVO(HospitalMaterialRequest request) {
        String hospitalId = UserUtils.getHospitalId();
        return this.baseMapper.listVO(new HospitalMaterialQueryRequest()
                .setHospitalId(hospitalId)
                .setInactive(HospitalMaterial.ACTIVATE)
                .setMaterialCode(request.getCode())
                .setBeginDate(request.getBeginDate())
                .setMaterialErpCode(request.getThirdMaterialId()));
    }

    @Override
    public CommonResult listForErp(MaterialRequest request) {
        QueryWrapper<HospitalMaterial> query = Wrappers.<HospitalMaterial>query()
                .eq("hospital_id", request.getHospitalId());
        if (!StringUtils.isAllBlank(request.getStartDate(), request.getEndDate())) {
            query.between("gmt_modified", request.getStartDate(), request.getEndDate());
        } else {
            return CommonResult.error("请正确填写起止日期");
        }
        List<HospitalMaterial> list = this.list(query);
        List<MaterialVO> vos = BeanUtils.copyProperties(list, MaterialVO.class);
        return CommonResult.ok("成功", vos);
    }

    /**
     * 第三方接口，添加或修改医院商品信息
     * 1、没有传递耗材编码的，由系统自动生成，否则取现成的
     *
     * @param dtos
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> batchSave(List<HospitalMaterialDTO> dtos) {
        log.info("==============医院商品批量保存开始=================");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        int insertSize = 0;
        int updateSize = 0;
        String hospitalId = UserUtils.getHospitalId();
        log.info("医院Id:{}", hospitalId);
        //String hospitalId = "1269151868856586242";

        List<String> supplierIds = dtos.parallelStream().map(o -> o.getSupplierId()).distinct().collect(Collectors.toList());
        List<String> manufactureNames = dtos.parallelStream().map(o -> o.getManufacturerName()).distinct().collect(Collectors.toList());
        List<String> materialNames = dtos.parallelStream().map(o -> o.getMaterialName()).distinct().collect(Collectors.toList());
        List<String> materialCodes = dtos.parallelStream().map(o -> o.getMaterialCode()).distinct().collect(Collectors.toList());
        /** 批量生成编码 */
        int grCodecount = (int) dtos.stream().filter(o -> StringUtils.isBlank(o.getMaterialCode())).count();
        List<String> codes = Lists.newArrayListWithExpectedSize(grCodecount);
        if (grCodecount > 0) {
            codes = SerialUtils.batchGenerateCode(
                    SerialRuleConsts.BASE_HOSPITAL_MATERIAL_CODE, SerialOwnerUtils.getHospitalOwner(hospitalId), grCodecount
            );
        }
        int codeIndex = 0;

        ArrayList<String> returnCodeList = Lists.newArrayListWithExpectedSize(grCodecount);

        List<HospitalSupplier> hsList = Lists.newArrayList();
        List<Supplier> supplierList = Lists.newArrayList();
        if (supplierIds != null && supplierIds.size() > 0) {
            hsList = hospitalSupplierMapper.selectList(
                    Wrappers.<HospitalSupplier>query()
                            .select("supplier_id")
                            .eq("hospital_id", hospitalId)
                            .in("supplier_id", supplierIds)
            );

            Set<String> supplierIdList = hsList.stream().map(o -> o.getSupplierId())
                    .collect(Collectors.toSet());
            if(supplierIdList != null && !supplierIdList.isEmpty()){
                supplierList = supplierService.list(
                        Wrappers.<Supplier>query().select("id,name")
                                .in("id", supplierIdList)
                );
            }
        }

        Map<String, Supplier> supplierMap = supplierList.stream().collect(Collectors.toMap(o -> o.getId(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条供应商数据", supplierMap.size());

        Set<String> supplierIdList = supplierList.stream().map(o -> o.getId()).collect(Collectors.toSet());
        List<Manufacturer> mfgList = Lists.newArrayList();
        if (manufactureNames != null && manufactureNames.size() > 0 && supplierIdList != null && supplierIdList.size() > 0) {
            mfgList = manufacturerService.list(
                    Wrappers.<Manufacturer>query()
                            .select("id,name,supplier_id")
                            .in("supplier_id", supplierIdList)
                            .in("name", manufactureNames)
            );
        }
        Map<String, Manufacturer> mfgMap = mfgList.stream().collect(Collectors.toMap(o -> o.getSupplierId() + o.getName(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条厂商数据", mfgMap.size());


        List<Material> materialList = Lists.newArrayList();
        if (materialNames != null && materialNames.size() > 0 && supplierIdList != null && supplierIdList.size() > 0) {
            materialList = materialService.list(
                    Wrappers.<Material>query().select("id", "material_name", "material_trade_name", "certificate_no", "supplier_id", "manufacturer_id")
                            .in("supplier_id", supplierIdList)
                            .in("material_name", materialNames)
            );
        }
        Map<String, Material> materialMapById = materialList.stream().collect(
                Collectors.toMap(o -> o.getId(), o -> o, (o1, o2) -> o1)
        );
        log.info("加载到{}条耗材数据", materialMapById.size());

        List<String> materialIdList = materialList.stream().map(o -> o.getId()).collect(Collectors.toList());
        Map<String, MaterialSpec> specMapByMaterialId = new HashMap<>();
        if (materialIdList.size() > 0) {
            List<MaterialSpec> materialSpecList = materialSpecService.list(
                    Wrappers.<MaterialSpec>query().select("id", "material_id", "material_spec", "price", "unit", "order_qty", "order_unit", "is_one_thing_one_yard", "is_consignment")
                            .in("material_id", materialIdList)
            );
            specMapByMaterialId = materialSpecList.stream().collect(
                    Collectors.toMap(o -> o.getMaterialId(), o -> o, (o1, o2) -> o1)
            );
            log.info("加载到{}条品规数据", specMapByMaterialId.size());
        } else {
            log.info("加载到0条品规数据");
        }

        /*List<String> materialIdList = materialList.stream().map(o -> o.getId()).collect(Collectors.toList());
        List<MaterialSpec> materialSpecList = materialSpecService.list(
                Wrappers.<MaterialSpec>query().select("id", "material_id", "material_spec", "price", "unit", "order_qty", "order_unit", "is_one_thing_one_yard", "is_consignment")
                        .in("material_id", materialIdList)
        );
        Map<String, MaterialSpec> specMap = materialSpecList.stream().collect(
                Collectors.toMap(o -> o.getMaterialId() + o.getMaterialSpec(), o -> o, (o1, o2) -> o1)
        );
        log.info("加载到{}条品规数据", specMap.size());*/

        List<HospitalMaterial> hmList = Lists.newArrayList();
        if (materialCodes != null && materialCodes.size() > 0) {
            hmList = this.list(
                    Wrappers.<HospitalMaterial>query().select("id", "material_id", "material_code", "material_spec_id", "material_spec", "manufacturer_id", "gmt_modified_lms")
                            .eq("hospital_id", hospitalId)
                            .in("material_code", materialCodes)
            );
        }
        Map<String, HospitalMaterial> hospitalMaterialMapByMaterialCode = hmList.stream().collect(
                Collectors.toMap(o -> o.getMaterialCode(), o -> o, (o1, o2) -> o1)
        );
        log.info("加载到{}条医院商品数据", hospitalMaterialMapByMaterialCode.size());

        List<MaterialApplicantAddBatchDto> applicantAddBatchDtoList = Lists.newArrayList();
        MaterialApplicantAddBatchDto applicantAddBatchDto;
        HospitalMaterial hospitalMaterialFind = null;
        for (HospitalMaterialDTO dto : dtos) {
            HospitalMaterial hm = new HospitalMaterial();
            String supplierId = dto.getSupplierId();
            String materialCode = dto.getMaterialCode();
            String mfgName = dto.getManufacturerName();
            String materialName = dto.getMaterialName();
            String materialSpec = dto.getMaterialSpec();

            // 是否新耗材
            hospitalMaterialFind = hospitalMaterialMapByMaterialCode.get(materialCode);
            boolean isNewHm = hospitalMaterialFind == null;
            // 没做修改的
            if (hospitalMaterialFind != null && ObjectUtil.equal(hospitalMaterialMapByMaterialCode.get(materialCode).getGmtModifiedLms(),dto.getGmtModifiedLms())) {
                returnCodeList.add(hospitalMaterialMapByMaterialCode.get(materialCode).getMaterialCode());
                continue;
            }
            if (hospitalMaterialFind == null) {
                hospitalMaterialFind = new HospitalMaterial();
            }

            hm.setMaterialCode(StringUtils.isBlank(materialCode) ? codes.get(codeIndex++) : materialCode);

            Manufacturer mf = mfgMap.get(supplierId + mfgName);
            if (mf == null) {
                //添加厂商信息
                mf = new Manufacturer();
                String pinyin = PinYinUtils.getAlpha(mfgName);
                manufacturerService.save(mf.setSupplierId(supplierId)
                        .setName(mfgName)
                        .setPinyin(StringUtils.substring(pinyin, 0, 10)));
                mfgMap.put(supplierId + mfgName, mf);
            }

            hm.setManufacturerId(mf.getId());
            hm.setManufacturerName(mf.getName());

            // 根据商品名称，供应商id 查询商品是否存在
            Material m = materialMapById.get(hospitalMaterialFind.getMaterialId());
            if (isNewHm) {
                //添加商品信息
                String pinyin = PinYinUtils.getAlpha(materialName);
                m = new Material().setSupplierId(supplierId)
                        .setCatalogId("0")
                        .setMaterialTypeCode(Material.TYPE_CODE_CONSUMABLES +"")
                        .setMaterialName(materialName)
                        .setMaterialTradeName(dto.getMaterialTradeName())
                        .setMaterialErpCode(dto.getMaterialErpCode())
                        .setPinyin(StringUtils.substring(pinyin, 0, 30));
                m.setId(IdWorker.getIdStr());

                // 医保信息
                m.setHisMedicareNo(dto.getHisMedicareNo()).setHisMedicareName(dto.getHisMedicareName())
                        .setHisMedicareNo2(dto.getHisMedicareNo2()).setHisMedicareName2(dto.getHisMedicareName2());

                // 注册证信息
                m.setCertificateNo(dto.getCertificateNo())
                        .setCertificateExpiredStartDate(dto.getCertificateExpiredStartDate())
                        .setCertificateExpiredDate(dto.getCertificateExpiredDate());

                m.setManufacturerId(mf.getId())
                        .setManufacturerName(mf.getName());

                materialService.save(m);
                materialMapById.put(m.getId(),m);
            } else{
                if (m == null) {
                    BusinessException.throwError(
                            "未找到供货商品对应的商品信息，请检查,商品名称[{}]，商品编码[{}]，商品ID[{}]",
                            hospitalMaterialFind.getMaterialName(),
                            hospitalMaterialFind.getMaterialCode(),
                            hospitalMaterialFind.getMaterialId()
                    );
                }
                // 医保信息
                m.setHisMedicareNo(dto.getHisMedicareNo()).setHisMedicareName(dto.getHisMedicareName())
                        .setHisMedicareNo2(dto.getHisMedicareNo2()).setHisMedicareName2(dto.getHisMedicareName2());

                // 注册证信息
                m.setCertificateNo(dto.getCertificateNo())
                        .setCertificateExpiredStartDate(dto.getCertificateExpiredStartDate())
                        .setCertificateExpiredDate(dto.getCertificateExpiredDate());

                m.setManufacturerId(mf.getId())
                        .setManufacturerName(mf.getName());
                materialService.updateById(m);

            }
            if(supplierMap.get(supplierId) == null){
                returnCodeList.add(hm.getMaterialCode());
                log.error("供应商不存在"+ supplierId);
                continue;
            }
            hm.setMaterialId(m.getId())
                    .setMaterialName(m.getMaterialName())
                    .setMaterialErpCode(dto.getMaterialErpCode())
                    .setMaterialTradeName(dto.getMaterialTradeName())
                    .setCertificateNo(dto.getCertificateNo())
                    .setCertificateExpiredDate(dto.getCertificateExpiredDate())
                    .setCertificateExpiredStartDate(dto.getCertificateExpiredStartDate())
                    .setSupplierId(supplierId)
                    .setSupplierName(supplierMap.get(supplierId).getName());
            hm
                    .setMaterialSpec(dto.getMaterialSpec())
                    .setForm(dto.getForm())
                    .setPrice(dto.getPrice())
                    .setUnit(dto.getUnit())
                    .setIsConsignment(dto.getIsConsignment())
                    .setIsOneThingOneYard(dto.getIsOneThingOneYard())
                    .setHospitalId(hospitalId)
                    .setMaterialHrpCode(dto.getMaterialHrpCode())
                    .setIsSunPurchase(dto.getIsSunPurchase())
                    .setSunPurchaseCode(dto.getSunPurchaseCode())
                    .setSunPurchaseSpecId(dto.getSunPurchaseSpecId())
                    .setMedicalConsumablesCode(dto.getMedicalConsumablesCode())
                    .setBidno(dto.getBidno())
                    .setUdi(dto.getUdi())
                    .setHospitalCatalogCode(dto.getHospitalCatalogCode());
            hm.setHisMedicareNo(dto.getHisMedicareNo()).setHisMedicareName(dto.getHisMedicareName())
                    .setHisMedicareNo2(dto.getHisMedicareNo2()).setHisMedicareName2(dto.getHisMedicareName2())
                    .setGmtModifiedLms(dto.getGmtModifiedLms())
                    .setHospitalCatalogId(dto.getHospitalCatalogId()).setHospitalCatalogName(dto.getHospitalCatalogName()).setHospitalCatalogId(dto.getHospitalCatalogId())
            ;

            Double orderQty = dto.getOrderQty();
            String orderUnit = dto.getOrderUnit();

            //根据商品id 商品规格查询商品品规是否存在
            MaterialSpec materialSpecFind = null;
            if (specMapByMaterialId != null) {
                materialSpecFind = specMapByMaterialId.get(m.getId());
            }
            //MaterialSpec ms = specMap.get(m.getId() + materialSpec);
            //如果品规不存在

            if (materialSpecFind == null) {
                //添加品规
                materialSpecFind = new MaterialSpec().setMaterialId(hm.getMaterialId())
                        .setMaterialErpCode(hm.getMaterialErpCode())
                        .setMaterialSpec(materialSpec)
                        .setInputCodingType(0+"")
                        .setForm(dto.getForm())
                        .setOrderQty(orderQty == 0 ? 1.0 : orderQty)
                        .setOrderUnit(StringUtils.defaultIfBlank(orderUnit, dto.getUnit()))
                        .setUnit(dto.getUnit())
                        .setPrice(dto.getPrice())
                        .setIsConsignment(dto.getIsConsignment())
                        .setCertificateNo(dto.getCertificateNo())
                        .setCertificateExpiredDate(dto.getCertificateExpiredDate())
                        .setCertificateExpiredStartDate(dto.getCertificateExpiredStartDate())
                        .setIsOneThingOneYard(dto.getIsOneThingOneYard());
                materialSpecService.save(materialSpecFind);
                specMapByMaterialId.put(m.getId(), materialSpecFind);
                hm.setMaterialSpecId(materialSpecFind.getId());

                applicantAddBatchDto = new MaterialApplicantAddBatchDto();
                applicantAddBatchDto.setMaterialId(materialSpecFind.getMaterialId()).setMaterialSpecId(materialSpecFind.getId()).setSupplierId(supplierId).setHospitalId(hospitalId);
                applicantAddBatchDtoList.add(applicantAddBatchDto);
            } else{
                BeanUtils.copyProperties(dto,materialSpecFind, "id");
                materialSpecService.updateById(materialSpecFind);
            }

            if (isNewHm) {
                hm
                        .setOrderQty((orderQty == null || orderQty == 0) ? materialSpecFind.getOrderQty() : orderQty)
                        .setOrderUnit(StringUtils.defaultIfBlank(orderUnit, dto.getUnit()))
                ;
            }
            // 是否启用
            if ( dto.getInactive() == 1) {
                hm.setInactive(HospitalMaterial.DEACTIVATE);
            } else {
                hm.setInactive(HospitalMaterial.ACTIVATE);
            }

            if (!isNewHm) {
                hm.setId(hospitalMaterialMapByMaterialCode.get(dto.getMaterialCode()).getId());
                this.updateById(hm);
                updateSize++;
            } else {
                this.save(hm);
                insertSize++;
            }
            returnCodeList.add(hm.getMaterialCode());
        }

        //存在新增商品，则增加相关商品的供货申请单
        if (ObjectUtil.length(applicantAddBatchDtoList) > 0) {
            SpringUtils.getBean(MaterialApplicantServiceImpl.class).saveBatchWithPass(applicantAddBatchDtoList);
        }


        stopWatch.stop();

        int failCnt = dtos.size() - insertSize - updateSize;
        log.info("==============医院商品批量保存结束，共处理{}条数据，耗时：{}，修改{}条，新增{}条，失败{}条=================",
                dtos.size(), stopWatch.getTotalTimeSeconds(), updateSize, insertSize, failCnt);

        return returnCodeList;
    }


    @Override
    public void active(String id) {
        HospitalMaterial hm = this.getById(id);
        if (hm == null) {
            return;
        }

        //当前状态是否是停用状态
        if (hm.getInactive() != HospitalMaterial.DEACTIVATE) {
            return;
        }
        //判断单位单价订单单位订单数量是否为空
        if (StringUtils.isBlank(hm.getUnit()) || hm.getPrice() == null
                || StringUtils.isBlank(hm.getOrderUnit()) || hm.getOrderQty() == null) {
            throw new BusinessException("单位、单价、订单单位、订单数量均不能为空！");
        }
        //修改状态为正常状态
        HospitalMaterial hospitalMaterial = new HospitalMaterial();
        hospitalMaterial.setInactive(HospitalMaterial.ACTIVATE).setId(hm.getId());
        this.updateById(hospitalMaterial);
    }

    @Override
    public void deactive(String id) {
        HospitalMaterial hm = this.getById(id);
        if (hm == null) {
            return;
        }
        //当前状态是否是正常状态
        if (hm.getInactive() != HospitalMaterial.ACTIVATE) {
            return;
        }

        //修改状态为停用状态
        HospitalMaterial hospitalMaterial = new HospitalMaterial();
        hospitalMaterial.setInactive(HospitalMaterial.DEACTIVATE).setId(hm.getId());
        this.updateById(hospitalMaterial);
    }

    @Override
    public IPage<HospitalMaterial> pageByKeyword(HospitalMaterialQueryRequest request) {
        request.setHospitalId(UserUtils.getHospitalId());
        return baseMapper.pageByKeyword(request.getPage(), request);
    }

    @Override
    public int countForSupplier(HospitalMaterialQueryRequest request) {
        return baseMapper.countForSupplier(request.setSupplierId(UserUtils.getSupplierId()).setInactive(HospitalMaterial.ACTIVATE));
    }

    @Override
    public void allActive() {
        this.update(Wrappers.<HospitalMaterial>update()
                .eq("hospital_id", UserUtils.getHospitalId())
                .and(i -> i.isNotNull("unit").ne("unit", "")
                        .isNotNull("price")
                        .isNotNull("order_unit").ne("order_unit", "")
                        .isNotNull("order_qty"))
                .set("inactive", HospitalMaterial.ACTIVATE)
        );
    }

    @Override
    public void allInactive() {
        this.update(Wrappers.<HospitalMaterial>update()
                .eq("hospital_id", UserUtils.getHospitalId())
                .set("inactive", HospitalMaterial.DEACTIVATE)
        );
    }

    @Override
    public List<HospitalMaterial> listByHospital(String hospitalId, String supplierId) {
        List<HospitalMaterial> list = this.baseMapper.list(new HospitalMaterialQueryRequest().setHospitalId(hospitalId).setSupplierId(supplierId));
        return list;
    }

    /**
     * 根据品名、品规、供应商、医院获取耗材信息
     */
    @Override
    public HospitalMaterial getOneHospitalMaterial(HospitalMaterialRequest request) {
        return this.baseMapper.getOneHospitalMaterial(new HospitalMaterialQueryRequest()
                .setHospitalId(request.getHospitalId())
                .setMaterialCode(request.getCode())
                .setSupplierId(request.getSupplierId())
        );
    }


    public void batchInsertFromTodayCreateMaterial(String hospitalId) {

        // 查找出今日新增
        List<String> excludeColumns = Lists.newArrayList("creator", "gmtCreate", "modifier", "gmtModified");
        List<MaterialSpec> specs = materialSpecService.list(Wrappers.<MaterialSpec>query()
                .gt("gmt_create", DateUtils.format(new Date(), "yyyy-MM-dd 00:00:00"))
                .select(MaterialSpec.class, o -> !excludeColumns.contains(o.getProperty()))
        );

        List<HospitalMaterial> hses = Lists.newArrayListWithExpectedSize(specs.size());

        List<String> codes = SerialUtils.batchGenerateCode(SerialRuleConsts.BASE_HOSPITAL_MATERIAL_CODE,
                SerialOwnerUtils.getHospitalOwner(hospitalId), specs.size());
        int codeIndex = 0;
        HospitalMaterial hs = null;
        for (MaterialSpec spec : specs) {
            hs = new HospitalMaterial();
            BeanUtils.copyProperties(spec, hs);

            hs.setMaterialSpecId(spec.getId());
            hs.setMaterialCode(codes.get(codeIndex));
            hs.setInactive(HospitalMaterial.ACTIVATE);

            hs.setHospitalId(hospitalId);
            hses.add(hs);
        }

        if (hses.isEmpty()) {
            return;
        }
        this.saveBatch(hses);

    }

    @Override
    protected ExcelImportResult doExcelImport(MultipartFile multipartFile, Map<String, Object> params) throws Exception {
        ImportParams importParams = PoiUtils.getDefaultImportParams();

        long currentTimeMillis = System.currentTimeMillis();
        ExcelImportResult importResult = PoiUtils.importExcelMore(multipartFile.getInputStream(), ExcelHospitalMaterialDTO.class, importParams);
        log.info("文件加载耗时：{}", DateUtils.formatTime(System.currentTimeMillis() - currentTimeMillis));
        List<ExcelHospitalMaterialDTO> dtoList = Lists.newArrayList(importResult.getList());

        List<String> hospitalNameList = dtoList.parallelStream().map(o -> o.getHospitalName()).distinct().collect(Collectors.toList());
        if (hospitalNameList.isEmpty()) {
            throw new BusinessException("请确认医院名称是否已存在");
        }


        //查询出所有医院
        List<Hospital> hospitalList = hospitalService.list(Wrappers.<Hospital>query().select("id,name").in("name", hospitalNameList));
        if (hospitalList.size() > 1) {
            throw new BusinessException("只允许导入一家医院的数据，多家医院数据请分开导入");
        }

        Map<String, Hospital> hospitalMap = hospitalList.stream().collect(Collectors.toMap(o -> o.getName(), o -> o, (o1, o2) -> o1));

        List<String> hospitalIdList = hospitalList.stream().map(o -> o.getId()).collect(Collectors.toList());
        List<HospitalSupplier> hsList = hospitalSupplierMapper.selectList(
                Wrappers.<HospitalSupplier>query()
                        .select("supplier_id")
                        .in("hospital_id", hospitalIdList)
        );

        List<Supplier> supplierList = supplierService.list(
                Wrappers.<Supplier>query()
                        .select("id,name")
                        .in("id", hsList.stream().map(o -> o.getSupplierId()).collect(Collectors.toList()))
        );
        Map<String, Supplier> supplierMap = supplierList.stream().collect(Collectors.toMap(o -> o.getName(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条供应商数据", supplierMap.size());

        List<String> supplierIdList = supplierList.stream().map(o -> o.getId()).collect(Collectors.toList());
        List<Manufacturer> manufacturerList = manufacturerService.list(
                Wrappers.<Manufacturer>query()
                        .select("id,name,supplier_id")
                        .in("supplier_id", supplierIdList)
        );
        Map<String, Manufacturer> manufacturerMap = manufacturerList.stream().collect(Collectors.toMap(o -> o.getSupplierId() + o.getName(), o -> o, (o1, o2) -> o1));
        log.info("加载到{}条厂商数据", manufacturerMap.size());

        List<Material> materialList = materialService.list(
                Wrappers.<Material>query().select("id", "material_name", "material_trade_name", "material_erp_code", "certificate_no", "supplier_id", "manufacturer_id", "catalog_id")
                        .in("supplier_id", supplierIdList)
        );
        Map<String, Material> materialMap = materialList.stream().collect(
                Collectors.toMap(o -> o.getSupplierId() + o.getManufacturerId() + o.getMaterialName(), o -> o, (o1, o2) -> o1)
        );
        log.info("加载到{}条耗材数据", materialMap.size());

        List<String> materialIdList = materialList.stream().map(o -> o.getId()).collect(Collectors.toList());
        List<MaterialSpec> materialSpecList = Lists.newArrayList();
        Map<String, MaterialSpec> materialSpecMap = null;
        if (materialIdList.size() > 0) {
            materialSpecList = materialSpecService.list(
                    Wrappers.<MaterialSpec>query().select("id", "material_id", "material_spec", "form", "price", "unit", "order_qty", "order_unit", "is_one_thing_one_yard", "is_consignment")
                            .in("material_id", materialIdList)
            );
            materialSpecMap = materialSpecList.stream().collect(
                    Collectors.toMap(o -> o.getMaterialId() + o.getMaterialSpec(), o -> o, (o1, o2) -> o1)
            );
            log.info("加载到{}条品规数据", materialSpecMap.size());
        } else {
            log.info("加载到0条品规数据");
        }
        /*List<MaterialSpec> materialSpecList = materialSpecService.list(
                Wrappers.<MaterialSpec>query().select("id", "material_id", "material_spec", "form", "price", "unit", "order_qty", "order_unit", "is_one_thing_one_yard", "is_consignment")
                        .in(materialIdList.size() > 0, "material_id", materialIdList)
        );
        Map<String, MaterialSpec> materialSpecMap = materialSpecList.stream().collect(
                Collectors.toMap(o -> o.getMaterialId() + o.getMaterialSpec(), o -> o, (o1, o2) -> o1)
        );
        log.info("加载到{}条品规数据", materialSpecMap.size());*/

        List<HospitalMaterial> hospitalMaterialList = this.list(
                Wrappers.<HospitalMaterial>query().select("id", "material_id", "material_code", "material_spec_id", "material_spec", "manufacturer_id")
                        .in("hospital_id", hospitalIdList)
        );
        Map<String, HospitalMaterial> hospitalMaterialMap = hospitalMaterialList.stream().collect(
                Collectors.toMap(o -> o.getMaterialId() + o.getMaterialSpec() + o.getMaterialCode() + o.getManufacturerId(), o -> o, (o1, o2) -> o1)
        );
        log.info("加载到{}条医院商品数据", hospitalMaterialMap.size());


        ConcurrentLinkedQueue<HospitalMaterial> hmUpdates = new ConcurrentLinkedQueue();
        ConcurrentLinkedQueue<HospitalMaterial> hmInserts = new ConcurrentLinkedQueue();

        Map<String, MaterialSpec> finalMaterialSpecMap = materialSpecMap;
        DefaultSaveHandler<ExcelHospitalMaterialDTO> saveHandler = new DefaultSaveHandler<ExcelHospitalMaterialDTO>() {
            @Override
            public void doSave(int currentIndex, ExcelHospitalMaterialDTO entity) throws BusinessException {
                ExcelHospitalMaterialDTO ehmDTO = entity;
                HospitalMaterial hm = new HospitalMaterial();
                BeanUtils.copyProperties(ehmDTO, hm);
                String supplierName = ehmDTO.getSupplierName();
                Supplier supplier = supplierMap.get(supplierName);

                Hospital hospitals = hospitalMap.get(ehmDTO.getHospitalName());
                if (hospitals == null) {
                    importResult.getList().remove(ehmDTO);
                    ehmDTO.setErrorMsg(String.format("医院不存在"));
                    importResult.getFailList().add(ehmDTO);
                    log.warn("第{}行医院不存在，请先确认数据是否正确；医院名称：{}", ehmDTO.getRowNum(), ehmDTO.getHospitalName());
                    return;
                    // continue;
                }
                hm.setHospitalId(hospitals.getId());

                if (supplier == null) {
                    importResult.getList().remove(ehmDTO);
                    ehmDTO.setErrorMsg(String.format("供应商不存在或未与医院建立关系"));
                    importResult.getFailList().add(ehmDTO);
                    log.warn("第{}行供应商不存在或未与医院建立关系，请先确认数据是否正确；供应商名称：{}", ehmDTO.getRowNum(), supplierName);
                    return;
                }

                ehmDTO.setManufacturerName(StringUtils.trim(ehmDTO.getManufacturerName()));
                Manufacturer manufacturer = manufacturerMap.get(supplier.getId() + ehmDTO.getManufacturerName());
                if (manufacturer == null) {
                    importResult.getList().remove(ehmDTO);
                    importResult.getFailList().add(ehmDTO);
                    ehmDTO.setErrorMsg(String.format("厂商不存在"));
                    log.warn("第{}行厂商不存在，请先确认数据是否正确；供应商名称：{}，厂商名称：{}", ehmDTO.getRowNum(), ehmDTO.getSupplierName(), ehmDTO.getManufacturerName());
                    return;
                }
                hm.setManufacturerId(manufacturer.getId());
                hm.setManufacturerName(manufacturer.getName());


                Material material = materialMap.get(supplier.getId() + hm.getManufacturerId() + hm.getMaterialName());
                if (material == null) {
                    importResult.getList().remove(ehmDTO);
                    importResult.getFailList().add(ehmDTO);
                    ehmDTO.setErrorMsg(String.format("商品不存在"));
                    log.warn("第{}行商品不存在，请先确认数据是否正确；商品名称：{}", ehmDTO.getRowNum(), hm.getMaterialName());
                    return;
                    //continue;
                }
                hm.setMaterialId(material.getId())
                        .setMaterialErpCode(material.getMaterialErpCode())
                        .setMaterialTradeName(material.getMaterialTradeName())
                        .setCertificateNo(material.getCertificateNo())
                        .setSupplierId(material.getSupplierId())
                        .setSupplierName(supplierName)
                        .setCatalogId(material.getCatalogId())
                ;

                MaterialSpec materialSpec = finalMaterialSpecMap.get(hm.getMaterialId() + hm.getMaterialSpec());
                if (materialSpec == null) {
                    importResult.getList().remove(ehmDTO);
                    importResult.getFailList().add(ehmDTO);
                    ehmDTO.setErrorMsg(String.format("商品品规不存在"));
                    log.warn("第{}行商品品规不存在，请先确认数据是否正确；商品品规：{}", ehmDTO.getRowNum(), hm.getMaterialSpec());
                    return;
                    //continue;
                }
                hm.setMaterialSpecId(materialSpec.getId())
                        .setForm(materialSpec.getForm())
                        .setOrderQty(materialSpec.getOrderQty())
                        .setOrderUnit(materialSpec.getOrderUnit())
                        .setUnit(materialSpec.getUnit())
                        .setPrice(materialSpec.getPrice())
                        .setIsConsignment(materialSpec.getIsConsignment())
                        .setIsOneThingOneYard(materialSpec.getIsOneThingOneYard());

                HospitalMaterial hospitalMaterial = hospitalMaterialMap.get(hm.getMaterialId() + hm.getMaterialSpec() + hm.getMaterialCode() + hm.getManufacturerId());
                if (hospitalMaterial != null) {
                    hm.setId(hospitalMaterial.getId());
                    hmUpdates.add(hm);
                } else {
                    hm.setInactive(HospitalMaterial.ACTIVATE); //default
                    hmInserts.add(hm);
                }
            }

        };
        BatchSaveTask<ExcelMaterialDTO> task = new BatchSaveTask(saveHandler, dtoList);

        this.forkJoinPool.invoke(task);

        if (!hmUpdates.isEmpty()) {
            this.updateBatchById(hmUpdates);
        }
        if (!hmInserts.isEmpty()) {
            // 批量生成编码
            List<HospitalMaterial> hmNeedCode = hmInserts.stream().filter(o -> StringUtils.isBlank(o.getMaterialCode())).collect(Collectors.toList());
            if (!hmNeedCode.isEmpty()) {
                List<String> codes = SerialUtils.batchGenerateCode(SerialRuleConsts.BASE_HOSPITAL_MATERIAL_CODE,
                        SerialOwnerUtils.getHospitalOwner(hospitalIdList.get(0)), hmNeedCode.size());
                AtomicInteger codeIndex = new AtomicInteger(0);
                hmNeedCode.stream().forEach(o -> o.setMaterialCode(codes.get(codeIndex.getAndIncrement())));
            }
            this.saveBatch(hmInserts);
        }
        return importResult;
    }

    @Override
    public IPage<HospitalMaterial> page(IPage<HospitalMaterial> page, Wrapper<HospitalMaterial> queryWrapper) {
        Integer count  =  this.baseMapper.selectCount(queryWrapper);
        ((Page)page).setSearchCount(false);
        page.setTotal(count);
        return this.baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdate(HospitalMaterial entity) {
        if (!entity.isNewRecord()) {
            Hospital hospital = hospitalService.getById(entity.getHospitalId());
            BusinessException.throwErrorIf(hospital == null, "所属医院不存在，请刷新");
            BusinessException.throwErrorIf(hospital.getFlagEnabledMaterialEdit() == null || !hospital.getFlagEnabledMaterialEdit(), "该医院尚未[启用商品编辑]，请刷新");
//            Material material = materialService.getOne(Wrappers.<Material>query().eq("id",entity.getMaterialId()));
//            BusinessException.throwErrorIf(material == null, "所属商品已删除，请刷新");
//            material.setManufacturerId(entity.getManufacturerId()).setManufacturerName(entity.getManufacturerName());
//            material.setCertificateNo(entity.getCertificateNo());
//            material.setCertificateExpiredStartDate(entity.getCertificateExpiredStartDate())
//                    .setCertificateExpiredDate(entity.getCertificateExpiredDate())
//                    .setHospitalCertificateExpiredStartDate(entity.getCertificateExpiredStartDate());
//            materialService.updateById(material);
//
//            MaterialSpec materialSpec = materialSpecService.getOne(Wrappers.<MaterialSpec>query().eq("id",entity.getMaterialSpecId()));
//            BusinessException.throwErrorIf(materialSpec == null, "所属规格已删除，请刷新");
//            materialSpec.setMaterialSpec(entity.getMaterialSpec()).setOrderUnit(entity.getOrderUnit()).setOrderQty(entity.getOrderQty());
//            materialSpec.setCertificateNo(entity.getCertificateNo())
//                    .setCertificateExpiredDate(entity.getCertificateExpiredDate())
//                    .setHospitalCertificateExpiredStartDate(entity.getCertificateExpiredStartDate());
//            materialSpecService.updateById(materialSpec);
        }

        return super.saveOrUpdate(entity);
    }


    //商品变更后，修改已供货商品
    @Override
    public void updateFromMaterialChange(Material entity) {
        List<HospitalMaterial> hospitalMaterialList = list(Wrappers.<HospitalMaterial>query().eq("material_id",entity.getId()));
        if (hospitalMaterialList.isEmpty()) {
            return;
        }

        for(HospitalMaterial hospitalMaterial : hospitalMaterialList) {
            BeanUtils.copyProperties(entity, hospitalMaterial, "id");
            MaterialSpec materialSpec = materialSpecService.getOne(Wrappers.<MaterialSpec>query().eq("id",hospitalMaterial.getMaterialSpecId()));
            BusinessException.throwErrorIf(materialSpec == null, "所属规格已删除，请刷新");
            BeanUtils.copyProperties(materialSpec, hospitalMaterial, "id");
            hospitalMaterial.setManufacturerName(entity.getManufacturerName());
            hospitalMaterial.setManufacturerId(entity.getManufacturerId());
            hospitalMaterial.setCertificateNo(entity.getCertificateNo());
            hospitalMaterial.setCertificateExpiredStartDate(entity.getCertificateExpiredStartDate());
            hospitalMaterial.setCertificateExpiredDate(entity.getCertificateExpiredDate());
        }
        updateBatchById(hospitalMaterialList);
    }
}

